队列的定义
像栈一样,队列(queue)也是表。只不过它限制了插入在一端进行而删除则在另一端进行。
队列的基本操作是enqueue(入队)
,它是在表的末端(叫作队尾(rear))插入一个元素;dequeue(出队)
,它是删除(并返回)表的开头(叫作表头(front))的元素。
队列的实现
和栈类似,任何可以用来实现表的方式都可以实现队列,对于每一种操作,链表实现和数组实现都给出快速的O(1)运行时间。队列的链表实现是最简单直接的,大家可以动手试一试。下面就将着重研究队列的数组实现,包括了 普通数组实现 和 循环数组 实现。
普通数组实现
在操作队列时,我们要能够直接索引到队列的头部和尾部以完成 enqueue
和 dequeue
操作。对于数组 arr
而言,我们就得存储队列头部 front
和尾部 rear
的 index
,而且这样一来,队列元素的个数可以也可以用 rear - front + 1
快速的计算得出!队列为空的条件就是 front = rear
。
对于 enqueue
操作而言,我们只需将 arr[++rear] = value
;对于 dequeue
操作而言, 我们只需将 front++
,可以说是十分方便。
但由于数组的长度是固定的,所以我们在使用普通数组实现队列之前,要估算一下数据规模,避免空间需求大于数组长度的情况。不过,我们可以用另一种方法:循环数组实现队列,这个方法不仅可以从一定程度上解决空间不够的问题,还避免了由于 dequeue
而造成的空间的浪费!
循环数组实现
循环数组不是一种新型的ADT,循环数组仍是一个普通的数组。循环二字指的是 空间上的循环:在 rear
指向队尾(rear++
将是一个不存在的位置)并且接收到了 enqueue
操作时,rear
绕回至数组的头部 继续进行存储操作。它的 enqueue
和 dequeue
操作和普通数组实现队列的操作方式一样,唯一区别就是在 rear = arr.length - 1
这个特殊的位置上!
用循环数组实现队列从一定程度上解决了空间不够的问题,但也不是意味着完全不需要去考虑数组容量。真正可以完全不用考虑容量问题的是用链表来实现队列。
具体代码实现
普通数组实现
1 | /** |
循环数组实现
1 | /** |